#include <stdx/all.h>
#include <http/HttpHelper.h>

static long num = 0;
static long cost = 0;
static long sucnum = 0;
static long errnum = 0;
static long avgcost = 0;
static long maxcost = -1;
static long mincost = 100000000;

static SpinMutex mtx;
static atomic_long runcnt(0);

class HttpWorkItem : public WorkItem
{
protected:
	string url;
	string cookie;
	HttpDataNode data;

public:
	void run()
	{
		++runcnt;

		long us;
		SmartBuffer rs;
		Timer tr(NULL, NULL);
		map<string, string> head;

		if (cookie.length() > 0)
		{
			head["Cookie"] = cookie;
		}

		rs = HttpHelper::GetResult(url, data.toString(), head);
		us = tr.getTimeGap();

		mtx.lock();

		num++;
		cost += us;
		avgcost = cost / num;

		if (us < mincost) mincost = us;
		if (us > maxcost) maxcost = us;

		if (rs.isNull())
		{
			LogTrace(eERR, "%d request failed", num);

			++errnum;
		}
		else
		{
			++sucnum;
		}

		mtx.unlock();
		
		--runcnt;
	}
	HttpWorkItem(const string& url, const string& data, const string& cookie)
	{
		this->url = url;
		this->cookie = cookie;
		this->data.parse(data);
	}
};

class MainApplication : public Application
{
protected:
	string url;
	long lastnum;
	time_t uptime;

public:
	bool main()
	{
		if (GetCmdParamCount() <= 1 || GetCmdParam("--help") || GetCmdParam("?"))
		{
			puts("  parameter list");
			puts("---------------------------");
			puts("  -u : test link");
			puts("  -d : post data");
			puts("  -f : post file");
			puts("  -c : test cookie");
			puts("  -p : test period");
			puts("  -t : test threads");
			puts("  -l : print record");
			puts("---------------------------");
			puts("");

			return true;
		}

		int delay = -1;
		int threads = 8;
		const char* param = GetCmdParam("-p");

		if (param)
		{
			delay = stdx::atoi(param);
			
			if (delay < 0) delay = 0;
		}

		string data;
		string cookie;

		if ((param = GetCmdParam("-u")) == NULL || *param == 0)
		{
			ColorPrint(eRED, "missing parameter[%s]\n", "-u");

			return false;
		}

		url = stdx::trim(param);

		if ((param = GetCmdParam("-d")) && *param) data = param;
		if ((param = GetCmdParam("-c")) && *param) cookie = param;
		if ((param = GetCmdParam("-t")) && *param) threads = stdx::atoi(param);
		if ((param = GetCmdParam("-f")) && *param) stdx::GetFileContent(data, param);

		if (threads < 1) threads = 1;
		if (threads > 100) threads = 100;

		TaskQueue::Instance()->start(threads);
		LogThread::Instance()->init("log");

		if (GetCmdParam("-l")) LogThread::Instance()->setLogFlag(2);

		lastnum = 0;
		uptime = time(NULL);

		while (true)
		{
			sp<HttpWorkItem> item = newsp<HttpWorkItem>(url, data, cookie);

			for (int i = 0; i < 10; i++)
			{
				if (stdx::async(item)) break;

				Sleep(100);
			}

			if (uptime < time(NULL)) printResult();

			if (delay > 0) usleep(delay);

			if (delay < 0) break;
		}

		TaskQueue::Instance()->wait();

		while (num == 0) Sleep(10);

		printResult();

		return true;
	}
	void printResult()
	{
		int flag = LogThread::Instance()->getLogFlag();

		while (runcnt > 0 || num == 0) Sleep(10);

		mtx.lock();

		LogThread::Instance()->wait();
		LogThread::Instance()->setLogFlag(2);

		time_t now = time(NULL);
		double cost = now - uptime;
		double times = sucnum - lastnum;

		if (cost < 1) cost = 1;

		LogTrace(eIMP, "process[%s] result\n"
				"------------------------------------------------------------------------------"
				"\n\t    rate : %d%%"
				"\n\t   times : %ld"
				"\n\t   speed : %.2f"
				"\n\t mincost : %ld(us)"
				"\n\t avgcost : %ld(us)"
				"\n\t maxcost : %ld(us)"
				"\n------------------------------------------------------------------------------\n",
				url.c_str(), 100 * sucnum / num, num, times / cost, mincost, avgcost, maxcost);

		uptime = now;
		lastnum = sucnum;

		LogThread::Instance()->wait();
		LogThread::Instance()->setLogFlag(flag);

		mtx.unlock();
	}
};

START_APP(MainApplication)
